//Orion's Standard Library
//Orion Sky Lawlor, 2/22/2000
//NAME:		osl/vector2d.h
//
//DESCRIPTION:	C++ 2-Dimentional vector library (no templates)
//
//This file provides various utility routines for easily
//manipulating 2-D vectors-- included are arithmetic,
//dot product, magnitude and normalization terms. 
//All routines are provided right in the header file (for inlining).
//
//Converted from osl/vector3d.h.
#pragma once

#include "OrionFlames.h"

#undef min //Microsoft Windows header file pollution.
#undef max

namespace OrionFlames
{
class Vector2d;

//Polar2d is a Point expressed in a 2D polar coordinate system--
//theta is the angle (counterclockwise) up from the x axis
//r is the distance of the Point from the origin.
class OFAPI Polar2d
{
public:
	//Nothing too useful can be done here, except convert to/from a Vector2d (see below)
	Polar2d() {} //Default constructor
	Polar2d(double Nr,double Nt) {r=Nr;theta=Nt;}
	Polar2d(const Vector2d &v);//Has to be declared below

	double r;//Distance from origin
	double theta;//Angle in radians
};

//Templated superclass, for vectors of other types:
//Vector's coordinates are of type T
//Vector operations return type Child
template <class T,class Child>
class OFAPI Vector2dT
{
	typedef Vector2dT<T,Child> this_t;

public:
	Vector2dT() { }
	
	//Simple 1-value constructor
	explicit Vector2dT(const T init) { x = y =init; }
	
	//2-value constructor
	Vector2dT(const T Nx, const T Ny) { x = Nx; y = Ny; }
	
	//2-value array constructor
	Vector2dT(const T *src) { x = src[0]; y = src[1]; }
	
	//Copy constructor
	Vector2dT(const this_t &copy) { x = copy.x; y = copy.y; }
	
	//Cast-to-T * operators (treat vector as array)
	operator T *() { return &x; }
	operator const T *() const { return &x; }

	//Arithmetic operations: these are carefully restricted to just those
	//that make unambiguous sense (to me... now...  ;-)
	//Counterexamples: vector*vector makes no sense (use .dot()) because
	//T/vector is meaningless (and we'd want a*b/b==a for b!=0), 
	//ditto for vector&vector (dot?), vector|vector (projection?), 
	//vector^vector (cross?),T+vector, vector+=T, etc.
	Child &operator =  (const this_t &b) { x = b.x; y = b.y; return *(Child *)this; }
	Child operator  +  (const this_t &b) const { return Child(x + b.x, y + b.y); }
	Child operator  +  (const Child &b) const { return Child(x + b.x, y + b.y); }
	Child operator  -  (const this_t &b) const { return Child(x - b.x, y - b.y); }
	Child operator  *  (const T scale) const { return Child(x * scale, y * scale); }
	Child operator  /  (const T &div) const {T scale = (T)1.0 / div; return Child(x * scale, y * scale); }
	Child operator  -  () const { return Child(-x, -y); }
	void operator   += (const this_t &b) { x += b.x; y += b.y; }
	void operator   -= (const this_t &b) { x -= b.x; y -= b.y; }
	void operator   *= (const T scale) { x *= scale; y *= scale; }
	void operator   /= (const T div) {T scale = 1 / div; x *= scale; y *= scale; }

	int operator == (const this_t &b) const { return ( x == b.x) && (y == b.y); }
	int operator != (const this_t &b) const { return ( x != b.x) || (y != b.y); }
	
	//Need a less-than to use vector in a std::map.
	bool operator < (const this_t &b) const
	{
		if (y < b.y) return true;
		if (y > b.y) return false;
		return x < b.x;	
	}

	//Vector specific operations.
	//Return the square of the magnitude of this vector.
	T magSqr() const { return x * x + y * y; }
	
	//Return the square of the distance to the vector b.
	T distSqr(const this_t &b) const { return (x - b.x) * (x - b.x) + (y - b.y) * (y - b.y); }

	//Return the CCW perpendicular vector.
	Child perp() const { return Child(-y, x); }
	
	//Return the signed area in parallelogram with given sides.
	T area(const this_t &o) const { return x * o.y - y * o.x; }

	//Perform a counterclockwise test between these three vertices.
	//returns > 0 if this->a->b is counterclockwise.
	T ccw(this_t a, this_t b) const
	{
		a -= *this;
		b -= *this;
		return a.x * b.y - a.y * b.x;
	}
	
	//Return this vector scaled by that.
	Child &scale(const this_t &b) { x *= b.x; y *= b.y; return *(Child *)this; }

	//Return the magnitude (length) of this vector.
	double mag() const { return sqrt(magSqr()); }
	
	//Return the distance to the vector b.
	double dist(const this_t &b) const { return sqrt(distSqr(b)); }
	
	//Return the dot product of this vector and b.
	double dot(const this_t &b) const { return x * b.x + y * b.y; }
	
	//Return the largest coordinate in this vector.
	T max() const { return (x > y) ? x : y; }
	
	//Make each of this vector's coordinates at least as big
	//as the given vector's coordinates.
	void enlarge(const this_t &by) { if (by.x > x) x = by.x; if (by.y > y) y = by.y; }
	
	//Swap coordinates so we are less, on each axis, than this value.
	void lessThan(this_t &p)
	{
		if (x > p.x) {T t = x; x = p.x; p.x = t; }
		if (y > p.y) {T t = y; y = p.y; p.y = t; }
	}

	T x,y;
};

//Vector2d is a cartesian vector in 2-space-- an x and y.
class OFAPI Vector2d : public Vector2dT<double, Vector2d>
{
public:
	Vector2d() { }
	
	//Simple 1-value constructor.
	explicit Vector2d(const double init) {x = y = init; }
	
	//Simple 1-value constructor.
	explicit Vector2d(int init) {x = y = init; }
	
	//2-value constructor.
	Vector2d(const double Nx,const double Ny) { x = Nx; y = Ny; }
	
	//Array constructors.
	Vector2d(const double *src) { x = src[0]; y = src[1]; }
	Vector2d(const float *src) { x = src[0]; y = src[1]; }
	Vector2d(const int *src) { x = src[0]; y = src[1]; }
	
	//Copy constructor.
	Vector2d(const Vector2d &copy) { x = copy.x; y = copy.y; }
	
	//Polar coordinates constructor.
	Vector2d(const Polar2d &p) { x = p.r * cos(p.theta); y = p.r * sin(p.theta); }

	//Vector-specific operations.
	//Return the cosine of the angle between this vector and b.
	double cosAng(const Vector2d &b) const { return dot(b) / (mag() * b.mag()); }
	
	//Return the "direction" (unit vector) of this vector.
	Vector2d dir() const { return (*this) / mag(); }

	//Return the counterclockwise angle this vector makes 
	//from the x axis, in radians.
	double angle() const { return atan2(y, x); }
};

//Vector2f is a cartesian vector in 2-space-- an x and y.
class OFAPI Vector2f : public Vector2dT<float,Vector2f>
{
public:
	Vector2f() { }
	
	//Simple 1-value constructor.
	explicit Vector2f(const double init) { x = y = (float)init; }

	//Simple 1-value constructor.
	explicit Vector2f(int init) { x = y = (float)init;}

	//2-value constructor.
	Vector2f(const double Nx, const double Ny) { x = (float)Nx; y = (float)Ny; }

	//Array constructors.
	Vector2f(const double *src) { x = (float)src[0]; y = (float)src[1]; }
	Vector2f(const float *src) { x = src[0]; y = src[1]; }
	Vector2f(const int *src) { x = (float)src[0]; y = (float)src[1]; }
};

//Allows "3.0 * vector2d" to work.
inline Vector2d operator*(const double scale, const Vector2d &v) {return Vector2d(v.x * scale, v.y * scale); }
inline Vector2f operator*(const double scale, const Vector2f &v) {return Vector2f(v.x * scale, v.y * scale); }

//Since this uses actual Vector2d fields & methods,
//it has to be declared down here.
inline Polar2d::Polar2d(const Vector2d &v)
{
	r = v.mag();
	theta = atan2(v.y, v.x);
}

//A 2d Pixel location.
class OFAPI Point : public Vector2dT<int,Point>
{
public:
	Point() { }
	Point(int val) : Vector2dT<int, Point>(val, val) { }
	Point(int x_, int y_) : Vector2dT<int, Point>(x_, y_) { }
	Point(const Vector2d &v) : Vector2dT<int, Point>((int)v.x, (int)v.y) { }
	
	// Return true if this point does not lie in these bounds.
	//"unsigned" allows us to avoid one test per axis.
	inline bool oob(unsigned int wid,unsigned int ht) const
	{
		//Subtle: if x is negative, (unsigned int)x is big.
		return ((unsigned int)x >= wid) || ((unsigned int)y >= ht);
	}
};
}
